use crate::{id, times};

// method call use [], others use ()
#[allow(unused_macros)]
macro_rules! pipe {
    ($value: expr) => {
        $value
    };

    // director call
    ($value: expr => $fun:ident) => {
        $fun($value)
    };

    // type convert
    ($value: expr => (as $type: ty)) => {($value as $type)};

    // method
    ($value: expr => [$method: ident]) => {
        $value.$method()
    };
    ($value: expr => [$method: ident ($($args: expr),*)]) => {
        $value.$method($($args,)*)
    };

    // fun call with args
    ($value: expr => ($fun:ident($($args: expr),*))) => {
        $fun($($args,)* $value)
    };

    // call expr like fun(value), write for closure
    ($value: expr => ($closure: expr)) => {
        $closure($value);
    };

    ($value: expr $(=> $callable: tt)+) => {{
        let result = $value;
        $(
            let result = pipe!(result => $callable);
        )*
        result
    }};
}

#[test]
fn test_pipe() {
    let a = pipe!(3 => id => (times(2, 3)) => (|x: i32| -x) => (as i64) => [abs] => (id));
    assert_eq!(a, 18);
    println!(
        "result is {}, hh: {}",
        pipe!(3 => (times(2, 3))),
        pipe!(3 => (|x| x + 3)),
        // pipe!(id(10) => id),
    );
}
